from game.dispatcher import Dispatcher, NotHandledError
from game.room import Room
from game.error import GameError

import uuid
import time
import logging

logger = logging.getLogger(__name__)

class Player(Dispatcher):
    @classmethod
    def clean(cls):
        logger.debug('Player clean: current objects %d', len(cls.objects))
        t_access = time.time() - 15 * 60
        t_disconnect = time.time() - 5 * 60
        for p in cls.objects.values():
            if p.last_access_time < t_access:
                p.delete()
            elif p.transport is None and p.disconnect_time < t_disconnect:
                p.delete()
        logger.debug('Player cleaned: current objects %d', len(cls.objects))

    @classmethod
    def generate_name(cls):
        cls.index += 1
        return 'player %d' % cls.index

    @classmethod
    def get(cls, id_):
        return cls.objects.get(id_, None)

    objects = {}
    index = 0
    def __init__(self):
        self.id = str(uuid.uuid1()).replace('-', '')
        self.objects[self.id] = self
        self.room = None
        self.transport = None
        self.name = self.generate_name()
        self.last_access_time = 0
        self.disconnect_time = 0

        self._refresh()

    def _refresh(self):
        self.last_access_time = time.time()

    def delete(self):
        logger.debug('%s:delete', self)
        self.leave_room()
        self.objects.pop(self.id, None)
        if self.transport:
            self.transport.close()

    def connect(self, transport):
        self.transport = transport

    def disconnect(self):
        self.transport = None
        self.disconnect_time = time.time()

    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, getattr(self, 'id', '?'))

    def enter_room(self, room):
        logger.debug('%s:enter_room %s', self, room)
        if self.room:
            if self.room.id == room.id:
                return

            self.leave_room()
        room.player_enter(self)
        self.room = room

    def leave_room(self):
        logger.debug('%s:leave_room %s', self, self.room)
        if self.room:
            self.room.player_leave(self)

    def __send(self, pack):
        logger.debug('%s:send %s', self, pack)
        if self.transport:
            self.transport.send(pack)

    def send(self, action, message):
        self.__send({
                        'action':action,
                        'data': message
                    })

    def recv(self, pack):
        logger.debug('%s:recv %s', self, pack)
        self._refresh()
        action = pack.get('action', None)
        message = pack.get('data', {})
        id_ = pack.get('id', None)

        if action is None:
            self.delete()
            return

        try:
            body = self.process_message(action, message)
            resp = {
                        'action':action,
                        'result':'ok',
                        'data': body
                    }
        except Exception, e:
            import traceback
            traceback.print_exc()
            resp = {
                    'action':action,
                    'result':'error',
                    'error': str(e)
                    }
        if id_:
            resp['id'] = id_
        self.__send(resp)


    def _handle_player_enter_room(self, message):
        room_id = message['room']
        room_type = message['type']
        room = Room.get(room_id)
        if room:
            if room.type == room_type:
                if self.room and self.room.id == room.id:
                    return
                if not room.is_full():
                    self.enter_room(room)
                else:
                    raise GameError('Room is full')
            else:
                raise GameError('Wrong room type')
        else:
            room = Room.create_room(room_type, room_id)
            self.enter_room(room)

    def _handle_player_set_profile(self, message):
        name = message['name']
        self.name = name

    def _handle_player_get_profile(self, message):
        return {
                    'name': self.name,
                    'id': self.id,
                }

    def _handle_room_info(self, message):
        if self.room:
            return {
                    'id': self.room.id,
                    'type': self.room.type,
                    }
        else:
            raise GameError('Not in room')

    def process_message(self, action, message):
        try:
            return self.dispatch(action, message)
        except NotHandledError:
            if self.room:
                return self.room.player_message(self, action, message)
            else:
                raise GameError('Unknown action')

